package cn.bellychang.linkedlist.bobo.cl02looplinkedlist;

import cn.bellychang.iiterface.liuxin.List;

/**
 * @author: bellychang
 * @date: 2020/2/12
 */
public class LinkedList<E> implements List<E> {

    private Node dummyHead;

    private int size;

    public LinkedList() {
        dummyHead = new Node(null);
        size = 0;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public void add(int index, E e) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException();
        }
        Node newNode = new Node(e);
        Node prevNode = dummyHead;
        for (int i = 0; i < index; i++) {
            prevNode = prevNode.next;
        }
        newNode.prev = prevNode;

        if (index == size) {
            newNode.next = prevNode;
        } else {
            newNode.next = prevNode.next;
        }

        prevNode.next = newNode;

        if (index == size) {
            prevNode.prev = newNode;
        } else {
            prevNode.next.prev = newNode;
        }
        size++;

    }

    @Override
    public void addLast(E e) {
        add(size, e);
    }

    public void addFirst(E e) {
        add(0, e);
    }

    @Override
    public E get(int index) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException();
        }
        Node prevNode = dummyHead;
        for (int i = 0; i < index; i++) {
            prevNode = prevNode.next;
        }
        return prevNode.next.value;
    }

    public E getFirst() {
        return get(0);
    }

    public E getLast() {
        return get(size - 1);
    }

    @Override
    public E remove(int index) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException();
        }
        Node prevNode = dummyHead;
        for (int i = 0; i < index; i++) {
            prevNode = prevNode.next;
        }

        Node retNode = prevNode.next;

        prevNode.next = retNode.next;
        if (index == size - 1) {
            retNode.next.prev = retNode.prev;
        } else {
            retNode.next.prev = prevNode.prev;
        }

        if (isEmpty()) {
            dummyHead.next = null;
            dummyHead.prev = null;
        }

        retNode.next = null;
        retNode.prev = null;

        size--;

        return retNode.value;
    }

    public E removeFirst() {
        return remove(0);
    }

    public E removeLast() {
        return remove(size - 1);
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        Node temp = dummyHead.next;
        for(int i = 0;i<size;i++){
            builder.append(temp.value)
                    .append("->");
            temp = temp.next;
        }
        return builder.length() >= 2 ? builder.toString().substring(0, builder.length() - 2) : builder.toString();
    }

    private class Node {
        private E value;
        private Node prev, next;

        public Node(E value) {
            this.value = value;
        }

        @Override
        public String toString() {
            return value.toString();
        }
    }
}
